package com.mall.shopping.services;

import com.alibaba.fastjson.JSON;
import com.mall.shopping.ICartService;
import com.mall.shopping.constant.GlobalConstants;
import com.mall.shopping.constants.ShoppingRetCode;
import com.mall.shopping.converter.CartItemConverter;
import com.mall.shopping.converter.ProductConverter;
import com.mall.shopping.dal.entitys.Item;
import com.mall.shopping.dal.persistence.ItemMapper;
import com.mall.shopping.dto.*;
import com.mall.shopping.utils.ExceptionProcessorUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Service;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.Map;


@Service
@Slf4j
public class CartServiceImpl implements ICartService {

    @Autowired
    RedissonClient redissonClient;

    @Autowired
    ItemMapper itemMapper;

    @Autowired
    ProductConverter productConverter;


    @Override
    public CartListByIdResponse getCartListById(CartListByIdRequest request) {

        request.requestCheck();

        CartListByIdResponse cartListByIdResponse = new CartListByIdResponse();
        cartListByIdResponse.setCode(ShoppingRetCode.SUCCESS.getCode());
        cartListByIdResponse.setMsg(ShoppingRetCode.SUCCESS.getMessage());

        try {
            Map<Object, Object> productMap = redissonClient.getMap(generatorCartItemKey(request.getUserId()));
            ArrayList<CartProductDto> cartProductDtos = new ArrayList<>();
            productMap.values().forEach(obj -> {
                CartProductDto cartProductDto = JSON.parseObject(obj.toString(), CartProductDto.class);
                cartProductDtos.add(cartProductDto);
            });
            cartListByIdResponse.setCartProductDtos(cartProductDtos);
        } catch (Exception e) {
            log.error("CartServiceImpl.getCartListById Occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(cartListByIdResponse, e);
        }

        return cartListByIdResponse;
    }

    private String generatorCartItemKey(long userId) {
        StringBuilder sb = new StringBuilder(GlobalConstants.CART_ITEM_CACHE_PREFIX);
        sb.append(":").append(userId);
        return sb.toString();
    }

    @Override
    public AddCartResponse addToCart(AddCartRequest request) {
        request.requestCheck();

        AddCartResponse addCartResponse = new AddCartResponse();
        addCartResponse.setCode(ShoppingRetCode.SUCCESS.getCode());
        addCartResponse.setMsg(ShoppingRetCode.SUCCESS.getMessage());


        try {
            Map<Object, Object> redissonClientMap = redissonClient.getMap(generatorCartItemKey(request.getUserId()));
            boolean exist = redissonClientMap.containsKey(request.getItemId());
            log.info("to add item " + request.getItemId() + " to" + generatorCartItemKey(request.getUserId()));
            CartProductDto cartProductDto = null;
            if (exist) {
                Object o = redissonClientMap.get(request.getItemId());
                cartProductDto = JSON.parseObject(o.toString(), CartProductDto.class);
                cartProductDto.setProductNum(cartProductDto.getProductNum() + request.getNum());
            } else {
                Item item = itemMapper.selectByPrimaryKey(request.getItemId().longValue());
                if (item == null) {
                    addCartResponse.setCode(ShoppingRetCode.SYSTEM_ERROR.getCode());
                    addCartResponse.setMsg(ShoppingRetCode.SYSTEM_ERROR.getMessage());
                    return addCartResponse;
                }
                cartProductDto = CartItemConverter.item2Dto(item);
                cartProductDto.setChecked("true");
                cartProductDto.setProductNum(request.getNum().longValue());
            }

            redissonClientMap.put(request.getItemId(), JSON.toJSON(cartProductDto).toString());
        } catch (Exception e) {
            log.error("CartServiceImpl.addToCart occurs error " + e);
            ExceptionProcessorUtils.wrapperHandlerException(addCartResponse, e);
        }
        return addCartResponse;
    }

    @Override
    public UpdateCartNumResponse updateCartNum(UpdateCartNumRequest request) {
        //log.info("start updateCartNum");
        request.requestCheck();

        UpdateCartNumResponse updateCartNumResponse = new UpdateCartNumResponse();
        updateCartNumResponse.setCode(ShoppingRetCode.SUCCESS.getCode());
        updateCartNumResponse.setMsg(ShoppingRetCode.SUCCESS.getMessage());

        try {
            String key = generatorCartItemKey(request.getUserId());
            log.info("to update " + key + "cart item " + request.getItemId());
            Map<Object, Object> redissonClientMap = redissonClient.getMap(key);
            Object o = redissonClientMap.get(request.getItemId());

            if (o != null) {
                CartProductDto cartProductDto = JSON.parseObject(o.toString(), CartProductDto.class);
                //数量若为0，可能需要删除
                log.info("before num = " + cartProductDto.getProductNum());
                cartProductDto.setProductNum(request.getNum().longValue());
                log.info("after num = " + cartProductDto.getProductNum());
                cartProductDto.setChecked(request.getChecked());
                redissonClientMap.put(request.getItemId(), JSON.toJSON(cartProductDto).toString());
            }
        } catch (Exception e) {
            log.error("CartServiceImpl.updateCartNum Occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(updateCartNumResponse, e);
        }

        return updateCartNumResponse;
    }

    @Override
    public CheckAllItemResponse checkAllCartItem(CheckAllItemRequest request) {
        request.requestCheck();

        CheckAllItemResponse checkAllItemResponse = new CheckAllItemResponse();
        checkAllItemResponse.setCode(ShoppingRetCode.SUCCESS.getCode());
        checkAllItemResponse.setMsg(ShoppingRetCode.SUCCESS.getMessage());

        try {
            RMap<Object, Object> redissonClientMap = redissonClient.getMap(generatorCartItemKey(request.getUserId()));
            redissonClientMap.values().stream().forEach(p -> {
                CartProductDto cartProductDto = JSON.parseObject(p.toString(), CartProductDto.class);
                cartProductDto.setChecked(request.getChecked());
                redissonClientMap.put(cartProductDto.getProductId(), JSON.toJSON(cartProductDto).toString());

            });
        } catch (Exception e) {
            log.error("CartServiceImpl.checkAllCartItem Occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(checkAllItemResponse, e);
        }
        return checkAllItemResponse;
    }

    @Override
    public DeleteCartItemResponse deleteCartItem(DeleteCartItemRequest request) {
        request.requestCheck();

        DeleteCartItemResponse deleteCartItemResponse = new DeleteCartItemResponse();
        deleteCartItemResponse.setCode(ShoppingRetCode.SUCCESS.getCode());
        deleteCartItemResponse.setMsg(ShoppingRetCode.SUCCESS.getMessage());
        log.info("to delete " + request.getItemId() + " from " + generatorCartItemKey(request.getUserId()));
        try {
            RMap<Object, Object> redissonClientMap = redissonClient.getMap(generatorCartItemKey(request.getUserId()));
            redissonClientMap.remove(request.getItemId());
        } catch (Exception e) {
            log.error("CartServiceImpl.deleteCartItem Occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(deleteCartItemResponse, e);
        }
        return deleteCartItemResponse;
    }

    @Override
    public DeleteCheckedItemResposne deleteCheckedItem(DeleteCheckedItemRequest request) {
        request.requestCheck();

        DeleteCheckedItemResposne deleteCheckedItemResposne = new DeleteCheckedItemResposne();
        deleteCheckedItemResposne.setCode(ShoppingRetCode.SUCCESS.getCode());
        deleteCheckedItemResposne.setMsg(ShoppingRetCode.SUCCESS.getMessage());

        log.info("to deleted checked items of " + generatorCartItemKey(request.getUserId()));
        try {
            RMap<Object, Object> redissonClientMap = redissonClient.getMap(generatorCartItemKey(request.getUserId()));

            redissonClientMap.values().stream().forEach(p -> {
                CartProductDto cartProductDto = JSON.parseObject(p.toString(), CartProductDto.class);
                if ("true".equals(cartProductDto.getChecked())) {
                    log.info("delete checked item: " + cartProductDto.getProductId());
                    redissonClientMap.remove(cartProductDto.getProductId());
                }
            });
        } catch (Exception e) {
            log.error("CartServiceImpl.deleteCheckedItem Occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(deleteCheckedItemResposne, e);
        }

        return deleteCheckedItemResposne;
    }

    @Override
    public ClearCartItemResponse clearCartItemByUserID(ClearCartItemRequest request) {
        ClearCartItemResponse response = new ClearCartItemResponse();
        response.setCode(ShoppingRetCode.SUCCESS.getCode());
        response.setMsg(ShoppingRetCode.SUCCESS.getMessage());
        log.info("start clearCartItemByUserID of " + request.getUserId() + "..." + request.getProductIds());
        try {
            RMap itemMap = redissonClient.getMap(generatorCartItemKey(request.getUserId()));
            itemMap.values().forEach(obj -> {
                CartProductDto cartProductDto = JSON.parseObject(obj.toString(), CartProductDto.class);
                if (request.getProductIds().contains(cartProductDto.getProductId())) {
                    log.info("to delete item" + cartProductDto.getProductId());
                    itemMap.remove(cartProductDto.getProductId());
                }
            });
        } catch (Exception e) {
            log.error("CartServiceImpl.clearCartItemByUserID Occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }
        return response;
    }
}
